CMake 에 대해
2025-1 컴퓨터비전 과목에서 처음으로 CMake 를 접하였다.
인턴쉽을 진행하며 교육자료로 사용할 ROS 패키지들을 개발하면서도 CMake 의 편의성을 여럿 느껴왔다. (ROS 에서는 catkin, colcon 빌드 시스템을 사용한다. 이는 CMake 를 ROS 시스템에 맞게 expand 한 것)
주제별로 subdirectory 를 두고 여러 소스코드를 한번에 컴파일하고 빌드할 수 있다는 점 그리고 복잡한 빌드 의존성을 쉽게 해결할 수 있다는 점이 신세계였다.
- cli 명령어로 소스코드를 빌드하는 경우, 헤더파일이랑 내외부라이브러리의 경로를 명시해서 링킹해주는 작업을 직접 해주어야한다.
- ex) g++ main.cpp -o main -I /usr/local/include/opencv -L /usr/local/bin -l opencv_core ...
참고로, cmake 자체는 빌드나 컴파일하는데 사용되지 않는다. 진짜 컴파일&빌드는 make 이 하는거고, cmake 는 빌드를 위한 빌드파일들을 생성하는 역할이다.
CMakeLists 를 작성하는 방법을 기록해놓고자한다.
1. workspace 생성하기
먼저, 작업공간을 만들자.
기본 틀은 아래와 같다.
cmake_ex
├── CMakeLists.txt ...(1)
└── src가장 상위 폴더에 CMakeLists.txt 를 생성해 현재 프로젝트의 메타데이터를 기록해두어야한다.
1.1 CMakeLists.txt
가장 상위 폴더의 CMakeLists.txt (1) 에는 아래처럼 작성하면 된다.
# CMakeLists.txt
cmake_minimum_required(VERSION 3.31)
project(cmake_ex
VERSION 1.0
DESCRIPTION "CMAKE 연습"
LANGUAGES CXX C)1.2 message()
VERSION 1.0 을 기입함에 따라 PROJECT_VERSION 같은 전역변수들이 생성되는데, message() 명령어로 확인할 수 있다.
# CMakeLists.txt
cmake_minimum_required(VERSION 3.31)
project(cmake_ex
VERSION 1.0
DESCRIPTION "CMAKE 연습"
LANGUAGES CXX C)
message("Proejct 버전 : ${PROJECT_VERSION}")
message("Proejct global path : ${PROJECT_SOURCE_DIR}")최상위 폴더에서 $ cmake . 을 실행하면 아래처럼 출력이 된다.
$ cmake .
Proejct 버전 : 1.0
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /Users/basamg/cpp/cmake_ex(참고: cmake . 생성물은 직접 삭제해주자.)
1.3 set()
직접 변수를 설정해줄 수도 있다. (set 명령어의 주 역할은 내부변수에 값을 넣어주는 것이긴 하다. 후술예정)
data 폴더를 생성하고,
cmake_ex
├── CMakeLists.txt
├── data
└── srcset 명령어로 DATA_DIR 이라는 변수를 직접 생성해보자
# CMakeLists.txt
cmake_minimum_required(VERSION 3.31)
project(cmake_ex
VERSION 1.0
DESCRIPTION "CMAKE 연습"
LANGUAGES CXX C)
set(DATA_DIR ${PROJECT_SOURCE_DIR}/data)
message("Proejct 버전 : ${PROJECT_VERSION}")
message("Proejct global path : ${PROJECT_SOURCE_DIR}")
message("DATA 폴더 : ${DATA_DIR}")아래 명령어를 실행해 DATA_DIR 변수를 확인할 수 있다. (이는 상속되어 하위 폴더에서 계속 사용할 수 있다.)
$ cmake .
...
...
Proejct 버전 : 1.0
Proejct global path : /Users/basamg/cpp/cmake_ex
DATA 폴더 : /Users/basamg/cpp/cmake_ex/data
...
...2. sub directory 생성하기
src 폴더 내에 ex1 폴더를 생성하고, CMakeLists.txt 를 생성하자. 아래처럼 만들면 된다.
cmake_ex
├── CMakeLists.txt
├── data
└── src
└── ex1 1
└── CMakeLists.txt ....(2)2.1 get_file_component() , string()
CMakeLists.txt (2) 를 아래처럼 작성해보자.
# ex1 1/CMakeLists.txt
get_filename_component(PROJECT_NAME ${CMAKE_CURRENT_LIST_DIR} NAME)
message("현재 프로젝트 이름 : ${PROJECT_NAME}")get_file_component 를 이용해 현재 프로젝트의 이름을 뽑아올 수 있다.
ex1 1 폴더로 들어가서 $ cmake . 명령어를 실행하면 아래와 같이 출력된다.
$ cmake .
...
...
현재 프로젝트 이름 : ex1 1
...
...위처럼 공백을 포함하는 경우에 대처하기 위해서 아래처럼 CMakeLists 를 수정하자.
# ex1 1/CMakeLists.txt
get_filename_component(PROJECT_NAME ${CMAKE_CURRENT_LIST_DIR} NAME)
message("현재 프로젝트 이름 : ${PROJECT_NAME}")
string(REPLACE " " "_" PROJECT_NAME ${PROJECT_NAME})
message("현재 프로젝트 이름 : ${PROJECT_NAME}")빌드를 진행하면 아래처럼 출력되는 것을 확인할 수 있다. (물론 폴더명에 공백을 쓰는 개발자는 없을 것이다)
$ cmake .
...
...
현재 프로젝트 이름 : ex1 1
현재 프로젝트 이름 : ex1_1
...
...2.2 set()
이제, 컴파일러에게 사용할 언어의 버전을 명시해줄 수 있다. cpp 를 비롯한 여러 언어들은 새로운 기능을 추가하고, 안정성 문제가 있는 기능들을 삭제하기도 하며 발전하고있다.
대표적인 예로, smart pointer 의 도입과, 템플릿 함수인 make_unique 제공 등등이 있다. 언어의 버전을 명시해놓지 않으면, 해당 코드를 실행하는 다른 환경에서 오류가 발생할 수 있다.
CMAKE_CXX_STANDARD 는 cmake 에서 사용하는 내부변수인데, set() 명령어로 직접 옵션을 달아줄 수 있다.
# ex1 1/CMakeLists.txt
get_filename_component(PROJECT_NAME ${CMAKE_CURRENT_LIST_DIR} NAME)
message("현재 프로젝트 이름 : ${PROJECT_NAME}")
string(REPLACE " " "_" PROJECT_NAME ${PROJECT_NAME})
message("현재 프로젝트 이름 : ${PROJECT_NAME}")
project(PROJECT_NAME
LANGUAGES CXX C
)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)3. 소스 코드 작성하기
hello world 출력하는 간단한 소스코드를 작성하자.
ex1 1/main.cpp 를 아래처럼 작성하자.
#include <iostream>
int main()
{ std::cout << "Hell World" << std::endl; }4. 실행파일 생성
"이제, 실행파일을 만들어라" 라는 규칙을 명시해주면 된다.
4.1 add_executable()
# ex1 1/CMakeLists.txt
get_filename_component(PROJECT_NAME ${CMAKE_CURRENT_LIST_DIR} NAME)
message("현재 프로젝트 이름 : ${PROJECT_NAME}")
string(REPLACE " " "_" PROJECT_NAME ${PROJECT_NAME})
message("현재 프로젝트 이름 : ${PROJECT_NAME}")
project(${PROJECT_NAME}
LANGUAGES CXX C
)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(${PROJECT_NAME} main.cpp)4.2 add_subdirectory()
최상위 폴더의 CMakeLists.txt 에 add_subdirectory() 명령어를 이용해 ex1 1 폴더를 빌드 시스템에 포함시키자.
# CMakeLists.txt
cmake_minimum_required(VERSION 3.31)
project(cmake_ex
VERSION 1.0
DESCRIPTION "CMAKE 연습"
LANGUAGES CXX C)
set(DATA_DIR ${PROJECT_SOURCE_DIR}/data)
message("Proejct 버전 : ${PROJECT_VERSION}")
message("Proejct global path : ${PROJECT_SOURCE_DIR}")
message("DATA 폴더 : ${DATA_DIR}")
add_subdirectory("${PROJECT_SOURCE_DIR}/src/ex1 1")5. 빌드
이제 최상위 폴더에서 build 폴더를 생성하자.
$ mkdir build && cd build
$ cmake .. 으로 빌드 파일을 생성하고, $ make 로 빌드하자.
실행파일이 build/src/ex1 1/ex1_1 로 생성된다.
현재 위치가 build 라면, $ ./src/ex1 1/ex1_1 를 실행하면!
![[2026-02-15_11-59-02.png]]